package models

import (
	"encoding/json"
	"fmt"
	"golang-blog/infrastructure/databases"
	"golang-blog/infrastructure/log"
	"time"

	"gorm.io/gorm"
)

// 标签   标签和文章之间的映射关系是多对多；故新建一个中间表存储映射关系
type PostTag struct {
	Id     int `gorm:"primary_key;auto_increment" json:"id"`
	PostId int `json:"post_id"` //文章Id
	TagId  int `json:"tag_id"`  //标签Id
	// Post      *PostTag `json:"post"`                            //文章
	// Tag       *Tag     `json:"tag"`                             //标签
	CreatedAt string `json:"create_at"`
	UpdatedAt string `json:"updated_at"`
	DeletedAt string `json:"deleted_at"`
}

func (ci *PostTag) String() string {
	a, _ := json.MarshalIndent(ci, "", "  ")
	return string(a)
}
func (a *PostTag) BeforeCreate(tx *gorm.DB) (err error) {
	a.CreatedAt = time.Now().Format("2006-01-02 15:04:05")
	a.UpdatedAt = a.CreatedAt
	return
}

// 修改tag的引用次数==无效
func (a *PostTag) AfterCreate(tx *gorm.DB) (err error) {
	rawSql := fmt.Sprintf("update tags set tags.cited_num = tags.cited_num + 1 where id= %v", a.TagId)
	log.Infof("post-tag  afterCreate: %v", rawSql)
	return databases.GetDB().Exec(rawSql).Error
}

func (a *PostTag) BeforeUpdate(tx *gorm.DB) (err error) {
	a.UpdatedAt = time.Now().Format("2006-01-02 15:04:05")
	return
}
func (a *PostTag) BeforeDelete(tx *gorm.DB) (err error) {
	a.DeletedAt = time.Now().Format("2006-01-02 15:04:05")
	return
}
func (a *PostTag) AfterDelete(tx *gorm.DB) (err error) {
	// 对tag表进行更新
	rawSql := fmt.Sprintf("update tags set cited_num=cited_num-1 where id='%v'", a.PostId)
	err = databases.GetDB().Exec(rawSql).Error
	return err
}

type PostTags struct {
	wheres PostTag
	Arts   []PostTag
	txn    *gorm.DB
}

func NewPostTag(tx *gorm.DB) *PostTags {
	if tx == nil {
		tx = databases.GetDB()
	}
	return &PostTags{
		txn:  tx,
		Arts: make([]PostTag, 1, 32),
	}
}

func (a *PostTags) With(art *PostTag) *PostTags {
	a.Arts[0] = *art
	return a
}
func (as *PostTags) Where(a *PostTag) *PostTags {
	as.wheres = *a
	return as
}
func (as *PostTags) FirstOrCreate() (*PostTag, error) {
	txn := as.txn.Debug().Where(&as.wheres).Attrs(&as.Arts)
	if err := txn.FirstOrCreate(&as.Arts[0]).Error; err != nil {
		return nil, err
	}
	return &as.Arts[0], nil
}
func (as *PostTags) Create() error {
	txn := as.txn.Debug().Model(&PostTag{})
	if err := txn.Create(&as.Arts).Error; err != nil {
		return err
	}
	return nil
}
func (as *PostTags) First() (*PostTag, error) {
	txn := as.txn.Debug().Model(&PostTag{}).Where(&as.wheres)
	if err := txn.First(&as.Arts).Error; err != nil {
		return nil, err
	}
	return &as.Arts[0], nil
}
func (a *PostTags) QueryRange(page, pageSize int) (*[]PostTag, int, int, error) {
	var (
		count     int64
		totalPage int
	)
	txn := a.txn.Debug().Model(&PostTag{}).Where(&a.wheres)
	if err := txn.Order("id").Offset((page - 1) * pageSize).Limit(pageSize).Find(&a.Arts).Error; err != nil {
		return nil, 0, 0, err
	}
	if err := txn.Count(&count).Error; err != nil {
		return nil, 0, 0, err
	}
	if int(count)%pageSize != 0 {
		totalPage = int(count)/pageSize + 1
	} else {
		totalPage = int(count) / pageSize
	}
	return &a.Arts, len((*a).Arts), totalPage, nil
}
func (a *PostTags) Update() error {
	txn := a.txn.Debug().Model(&PostTag{}).Where(&a.wheres)
	if err := txn.Updates(&a.Arts[0]).Error; err != nil {
		return err
	}
	return nil
}
func (a *PostTags) Delete() error {
	txn := a.txn.Debug().Model(&PostTag{}).Where(&a.wheres)
	if err := txn.Delete(&a.Arts).Error; err != nil {
		return err
	}
	return nil
}
func (a *PostTags) Counts() (int64, error) {
	var count int64
	txn := a.txn.Debug().Model(&PostTag{}).Where(&a.wheres)
	if err := txn.Count(&count).Error; err != nil {
		return 0, err
	}
	return count, nil
}

func (a *PostTags) Last() (*PostTag, error) {
	txn := a.txn.Debug().Model(&PostTag{}).Where(&a.wheres)
	if err := txn.Last(&a.Arts).Error; err != nil {
		return nil, err
	}
	return &a.Arts[0], nil
}
